﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Alex.Library.Web.Ajax.Exceptions;

namespace Alex.Library.Web.Ajax
{
    /// <summary>
    /// 方法信息处理类
    /// </summary>
    public class ObjectMethodHandler
    {
        /// <summary>
        /// 获取类的方法数组
        /// </summary>
        /// <param name="className">类完全限定名</param>
        /// <param name="inspectMethods">期望获取的方法名称数组，如果要获取全部方法则此值应为null.</param>
        /// <returns></returns>
        public static MethodInfo[] GetMethods(string className, string[] inspectMethods)
        {
            try
            {
                Type classType = null;
                foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
                {
                    classType = assembly.GetType(className);
                    if (classType != null)
                    {
                        if (classType.IsGenericType)
                        {
                            throw new Exception("暂不支持泛型类.");
                        }
                        MethodInfo[] methods = classType.GetMethods();
                        List<MethodInfo> result = new List<MethodInfo>();
                        foreach (MethodInfo method in methods)
                        {
                            object[] objs = method.GetCustomAttributes(typeof(AjaxMethodAttribute), false);
                            if (objs != null && objs.Length > 0)
                            {
                                //如果inspectMethods有值则要进行对比，符合条件的才能加入返回值列表
                                if (inspectMethods != null && inspectMethods.Length > 0)
                                {
                                    string name = (objs[0] as AjaxMethodAttribute).MethodName;
                                    if (String.IsNullOrEmpty(name))
                                    {
                                        name = method.Name;
                                    }
                                    if (Array.IndexOf<string>(inspectMethods, name) == -1)
                                    {
                                        continue;
                                    }
                                }
                                result.Add(method);
                            }
                        }
                        return result.ToArray();
                    }
                }

                throw new ClassNotFoundException();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取类的全部方法数组
        /// </summary>
        /// <param name="className">类完全限定名</param>
        /// <returns></returns>
        public static MethodInfo[] GetMethods(string className)
        {
            return GetMethods(className, null);
        }

        /// <summary>
        /// 获取指定方法在作为Ajax方法使用时的名称
        /// </summary>
        /// <param name="method">方法</param>
        /// <returns>如果此参数的AjaxMethod特性的Name不为空则去此Name否则返回方法名</returns>
        public static string GetAjaxScriptMethodName(MethodInfo method)
        {
            object[] objs = method.GetCustomAttributes(typeof(AjaxMethodAttribute), false);
            if (objs != null && objs.Length > 0)
            {
                string name = (objs[0] as AjaxMethodAttribute).MethodName;
                if (!String.IsNullOrEmpty(name))
                {
                    return name;
                }
            }
            return method.Name;
        }

        /// <summary>
        /// 根据名称和类型
        /// </summary>
        /// <param name="classType">类型</param>
        /// <param name="methodName">方法名或AjaxMethod特性中的Name</param>
        /// <param name="paramTypes">该方法的参数类型列表</param>
        /// <exception cref="MissingMethodException">MissingMethodException</exception>
        /// <returns>匹配的方法</returns>
        public static MethodInfo GetMethodByName(Type classType, string methodName, Type[] paramTypes)
        {            
            MethodInfo method = classType.GetMethod(methodName, paramTypes);
            
            if (method == null)
            {
                object[] objs = null;
                foreach (MethodInfo m in classType.GetMethods())
                {
                    objs = m.GetCustomAttributes(typeof(AjaxMethodAttribute), false);
                    if (objs != null && objs.Length > 0)
                    {
                        if ((objs[0] as AjaxMethodAttribute).MethodName == methodName)
                        {
                            method = m;
                            break;
                        }
                    }
                }
                if (method == null)
                {
                    throw new MissingMethodException();
                }
            }
            return method;
        }
    }
}
